﻿using System;
using System.Collections.Generic;
using System.IO;
using UnityEngine;
using Eb;

public class ClientAutoPatcher<TDef> : Component<TDef> where TDef : DefAutoPatcher, new()
{
    //-------------------------------------------------------------------------
    public VersionConfig mVersionConfig;
    Dictionary<string, string> mMapNeedDeleteAsset;
    Dictionary<string, string> mMapSameAsset;
    Queue<string> mQueueAlreadyLoadAsset;
    LoadAssetBundle mLoadAssetBundle;
    WWW mWWWGetServerVersionCfg;
    WWW mUpdateDataWWW;
    string mRemoteRootDir;
    byte[] mRemoteAssetInfo;
    float CurrentDataProgress;

    //-------------------------------------------------------------------------
    AutoPathcerPath AutoPathcerPath { get; set; }
    bool StepGetServerVersionCfg { get; set; }// 从自动更新服务器获取版本配置信息
    bool StepIsNeedBundlePatcher { get; set; }// 判定是否需要Bundle包更新
    bool StepBundlePatcher { get; set; }// Bundle包更新
    bool StepIsNeedResourcePatcher { get; set; }// 判定是否需要资源包更新
    bool StepGetServerResourceListInfo { get; set; }// 从自动更新服务器获取资源清单信息
    bool StepResourcePatcher { get; set; }// 资源包更新
    bool StepFinished { get; set; }// 完成自动更新

    //-------------------------------------------------------------------------
    public override void init()
    {
        EbLog.Note("ClientAutoPatcher.init()");

        StepGetServerVersionCfg = true;
        StepIsNeedBundlePatcher = false;
        StepBundlePatcher = false;
        StepIsNeedResourcePatcher = false;
        StepResourcePatcher = false;
        StepFinished = false;

        AutoPathcerPath = new AutoPathcerPath();
        mVersionConfig = new VersionConfig(AutoPathcerPath.combinePersistentDataPath("/PackInfo.txt"));
        mMapNeedDeleteAsset = new Dictionary<string, string>();
        mMapSameAsset = new Dictionary<string, string>();
        mQueueAlreadyLoadAsset = new Queue<string>();

        CurrentDataProgress = 0;
    }

    //-------------------------------------------------------------------------
    public override void release()
    {
        EbLog.Note("ClientAutoPatcher.release()");
    }

    //-------------------------------------------------------------------------
    public override void update(float elapsed_tm)
    {
        // 步骤：从自动更新服务器获取版本配置信息
        if (StepGetServerVersionCfg)
        {
            if (mWWWGetServerVersionCfg == null)
            {
                mWWWGetServerVersionCfg = new WWW(mVersionConfig.LocalVersionConfig.remote_version_url);

                //UiMbLoading loading = UiMgr.Instance.createUi<UiMbLoading>(_eUiLayer.Loading);
                //loading.setTips("检测版本中");
            }
            else if (mWWWGetServerVersionCfg.isDone)
            {
                if (!string.IsNullOrEmpty(mWWWGetServerVersionCfg.error))
                {
                    //UiMbLoading loading = UiMgr.Instance.createUi<UiMbLoading>(_eUiLayer.Loading);
                    //loading.setTips("下载版本信息失败::Error::" + mServerVersionWWW.error);

                    Debug.LogError(mWWWGetServerVersionCfg.error);
                }
                else
                {
                    mVersionConfig.loadRemoteVersionConfig(mWWWGetServerVersionCfg.text);
                }

                StepGetServerVersionCfg = false;
                StepIsNeedBundlePatcher = true;
                mWWWGetServerVersionCfg = null;
            }
        }

        // 步骤：判定是否需要Bundle包更新
        if (StepIsNeedBundlePatcher)
        {
            if (_remoteEqualsLocalBundleVersion())
            {
                // 程序包全部相同，不更新
                //UiMgr.Instance.destroyCurrentUi<UiMbLoading>();

                Debug.Log("程序包全部相同，不更新");
            }
            else
            {
                // 更新程序包界面
                Debug.Log("更新程序包界面");

                //UiMbLoading loading = UiMgr.Instance.createUi<UiMbLoading>(_eUiLayer.Loading);
                //loading.setTips("更新版本");
                //UiMbUpdate update = UiMgr.Instance.createUi<UiMbUpdate>(_eUiLayer.Loading);
                //update.setUpdateInfo("更新版本," + mVersionConfig.LocalVersionConfig.bundle_version + "版本到" + mVersionConfig.RemoteVersionConfig.bundle_version + "版本,是否更新?", _updateBundle, _cancelUpdate);

                StepBundlePatcher = true;
            }

            StepIsNeedBundlePatcher = false;
        }

        // 步骤：Bundle包更新
        if (StepBundlePatcher)
        {
            Application.OpenURL(mVersionConfig.RemoteVersionConfig.bundle_url);
            StepBundlePatcher = false;
        }

        // 步骤：判定是否需要资源包更新
        if (StepIsNeedResourcePatcher)
        {
            if (_remoteEqualsLocalDataVersion())
            {
                // 数据包全部相同，不更新
                //UiMgr.Instance.destroyCurrentUi<UiMbLoading>();
                Debug.Log("程序包/数据包全部相同，不更新");
            }
            else
            {
                // 更新数据包
                Debug.Log("更新数据包");
                //UiMbLoading loading = UiMgr.Instance.createUi<UiMbLoading>(_eUiLayer.Loading);
                //loading.setTips("更新数据");
                //UiMbUpdate update = UiMgr.Instance.createUi<UiMbUpdate>(_eUiLayer.Loading);
                //update.setUpdateInfo("更新数据," + mVersionConfig.LocalVersionConfig.data_version + "版本到" + mVersionConfig.RemoteVersionConfig.data_version + "版本,是否更新?", _updateData, _cancelUpdate);
                StepResourcePatcher = true;



            }

            StepIsNeedResourcePatcher = false;
        }

        // 步骤：从自动更新服务器获取资源清单信息
        if (StepGetServerResourceListInfo)
        {
            Caching.CleanCache();

            //UiMgr.Instance.destroyCurrentUi<UiMbUpdate>();
            //UiMbLoading loading = UiMgr.Instance.createUi<UiMbLoading>(_eUiLayer.Loading);
            //loading.setTips("更新数据中");

            if (mUpdateDataWWW == null)
            {
                mUpdateDataWWW = new WWW(mVersionConfig.RemoteVersionConfig.data_url);
                mRemoteRootDir = mVersionConfig.RemoteVersionConfig.data_url.Substring(
                    0, mVersionConfig.RemoteVersionConfig.data_url.LastIndexOf('/'));
            }
            else if (mUpdateDataWWW.isDone)
            {
                if (string.IsNullOrEmpty(mUpdateDataWWW.error))
                {
                    mRemoteAssetInfo = mUpdateDataWWW.bytes;
                    mVersionConfig.LoadRemotePackInfo(mUpdateDataWWW.text);
                    var map_need_loadasset = _getNeedLoadAsset();
                    _deleteOldAsset();

                    if (map_need_loadasset.Count <= 0)
                    {
                        mVersionConfig.changeLocalDataVersionToRemote();
                    }
                    else
                    {
                        mLoadAssetBundle = new LoadAssetBundle();
                        foreach (var i in map_need_loadasset)
                        {
                            mLoadAssetBundle.setNeedLoadAsset(i.Key, mRemoteRootDir + i.Key);
                        }
                    }
                }
                else
                {
                    //UiMbLoading loading = UiMgr.Instance.createUi<UiMbLoading>(_eUiLayer.Loading);
                    //loading.setLoadProgress(mUpdateDataWWW.progress, "更新数据错误 Error::" + mUpdateDataWWW.error);                        
                }

                mUpdateDataWWW = null;
                StepGetServerResourceListInfo = false;
                StepResourcePatcher = true;
            }
            else
            {
                //UiMbLoading loading = UiMgr.Instance.createUi<UiMbLoading>(_eUiLayer.Loading);
                //loading.setLoadProgress(mUpdateDataWWW.progress, "更新数据中..." + mUpdateDataWWW.error);
            }
        }

        // 步骤：资源包更新
        if (StepResourcePatcher)
        {
            mLoadAssetBundle.update(elapsed_tm);

            if (mLoadAssetBundle.AssetLoadDone)
            {
                _writeAssetInfoToLocal();

                mLoadAssetBundle = null;
                StepResourcePatcher = false;
                StepFinished = true;
            }
            else
            {
                //UiMbLoading loading = UiMgr.Instance.createUi<UiMbLoading>(_eUiLayer.Loading);
                float progress = 0;
                string msg = "";
                if (mLoadAssetBundle.IsLoadAsset)
                {
                    progress = mLoadAssetBundle.CurrentLoadProgress;
                    msg = "正在下载数据..." + mLoadAssetBundle.CurrentAssetName + " (" + mLoadAssetBundle.CurrentIndex + "/" + mLoadAssetBundle.TotalCount + ")";
                }
                else
                {
                    progress = mLoadAssetBundle.CurrentWriteProgress;
                    msg = "正在将数据写入本地..." + mLoadAssetBundle.CurrentAssetName + " (" + mLoadAssetBundle.CurrentIndex + "/" + mLoadAssetBundle.TotalCount + ")";
                }
                //loading.setLoadProgress(progress, msg);
            }
        }

        //CoApp.BundleVersion = mCheckVersion.mVersionConfig.LocalVersionConfig.bundle_version;
        //CoApp.DataVersion = mCheckVersion.mVersionConfig.LocalVersionConfig.data_version;

        //// 创建EtLogin
        //EntityMgr.createEntity<EtLogin>(null, CoApp.Entity);
        //EntityMgr.destroyEntity(Entity);
    }

    //-------------------------------------------------------------------------
    Dictionary<string, string> _getNeedLoadAsset()
    {
        Dictionary<string, string> map_needloadasset = new Dictionary<string, string>();

        Dictionary<string, string> map_remote_asset_info = mVersionConfig.MapRemoteAssetInfo;
        Dictionary<string, string> map_local_asset_info = mVersionConfig.MapLocalAssetInfo;
        foreach (var i in map_remote_asset_info)
        {
            string value = "";
            map_local_asset_info.TryGetValue(i.Key, out value);

            if (string.IsNullOrEmpty(value))
            {
                map_needloadasset.Add(i.Key, i.Value);
            }
            else
            {
                if (!i.Value.Equals(value))
                {
                    map_needloadasset.Add(i.Key, i.Value);
                }
                else
                {
                    mMapSameAsset.Add(i.Key, i.Value);
                }
            }
        }

        foreach (var i in map_local_asset_info)
        {
            if (!mMapSameAsset.ContainsKey(i.Key))
            {
                mMapNeedDeleteAsset.Add(i.Key, i.Value);
            }
        }

        return map_needloadasset;
    }

    //-------------------------------------------------------------------------
    void _deleteOldAsset()
    {
        foreach (var i in mMapNeedDeleteAsset)
        {
            //string path = MbMain.Instance.PathMgr.combinePersistentDataPath(i.Key);
            //if (Directory.Exists(path))
            //{
            //    Directory.Delete(path, true);
            //}
            //if (File.Exists(path))
            //{
            //    File.Delete(path);
            //}
        }
    }

    //-------------------------------------------------------------------------
    bool _remoteEqualsLocalBundleVersion()
    {
#if UNITY_EDITOR
        return true;
#else
        if (mVersionConfig.RemoteVersionConfig.bundle_version.Equals(mVersionConfig.LocalVersionConfig.bundle_version))
        {
            return true;
        }

        return false;
#endif
    }

    //-------------------------------------------------------------------------
    bool _remoteEqualsLocalDataVersion()
    {
        if (mVersionConfig.RemoteVersionConfig.data_version.Equals(mVersionConfig.LocalVersionConfig.data_version))
        {
            return true;
        }
        else
        {
            return false;
        }
    }

    //-------------------------------------------------------------------------
    void _writeAssetInfoToLocal()
    {
        byte[] read_buffer = new byte[1024 * 1024];
        using (MemoryStream rs = new MemoryStream(mRemoteAssetInfo))
        {
            int read_length = rs.Read(read_buffer, 0, read_buffer.Length);
            using (FileStream ws = new FileStream(mVersionConfig.LocalAssetInfoPath, FileMode.Create))
            {
                while (read_length > 0)
                {
                    ws.Write(read_buffer, 0, read_length);
                    read_length = rs.Read(read_buffer, 0, read_buffer.Length);
                }

                mVersionConfig.changeLocalDataVersionToRemote();
            }
        }
    }

    //-------------------------------------------------------------------------
    void _cancelUpdate()
    {
        Application.Quit();
    }
}
